#pragma once

#include <vector>
#include "graphics/Texture.h"
#include "Vector3df.h"


const float G_MAG = 9.81f;

class CParticleSystem
{

public:
	//Constructors/Init functions----------
	CParticleSystem();
	CParticleSystem(int x, int y, int z, int pcfg);
	CParticleSystem(int p); //To start with a certain # of particles
	~CParticleSystem();
	void initParams();
	void initSimulationStep();
	void initGrid(float *pars, float del);



	//Simulation/Update steps----------
	void Simulate();
	void handleCollisions();
	void updateGrid();
	void findNeighbors();
	void putNeighbors(Vector3df to, Vector3df from);
	void addParticles();
	void incIndex() {index += 1;} //increment the index
	


	//Kernel functions----------
	float W_poly6(Vector3df r, float h);
	Vector3df gradientW_poly6(Vector3df r, float h);
	float laplacianW_poly6(Vector3df r, float h);
	Vector3df gradientW_spiky(Vector3df r, float h);
	float laplacianW_viscosity(Vector3df r, float h);


	//Drawing functions----------
	void Draw();
	void drawTable();
	void drawGlass();
	void drawParticles();
	void drawSphere(double r, int lats, int longs); 
	void drawSphereAt(Vector3df loc, GLfloat c[3], bool alpha);
	void SetLighting(); 


	//Structures---------
	struct CParticle
	{
		CParticle(int i, Vector3df gridPoint); //Constructor defined in CParticleSystem.cpp
		CParticle(CParticle* p);
		void updateColor(float maxLen);

		Vector3df pos;
		Vector3df vel;
		int index;
		GLfloat c[3]; // Color of the particle
	};
	struct cell
	{
		std::vector<CParticle* > pcs;
	};

	bool debug; //For debugging purposes...!
	bool leapFrog; //If it's in leapfrog mode
	bool interaction; //If l/r/u key is pressed to add external force
	bool add; //If there are particles to be added
	Vector3df externalForce;

private:
	float deltaT;
	float MASS;
	float h; //smoothing length
	float k; //gas constant (depends on temperature)
	float rho0; //rest density
	float mew; //fluid viscosity
	float sigma; //surface tension coefficient (depends on materials that form the surface)
	float threshold; //color field gradient must be larger than threshold to evaulate surface tension force
	Vector3df gravity;
	float maxVecLen; //for updateColor() in CParticle
	float damping;
	int pConfig; 
	float pRadius;

	CTexture wood;
	double cy;//y offset for center of table/base of the box of particles
	int maxX, maxY, maxZ;
	int index; //the current index for a new particle
	bool first; //True only in first run through

	//std::vector<CParticle> mPts; //Can remove this for an octree
	std::vector<cell> mPts; //1D vector of cells
	std::vector< std::vector< std::vector<cell> > > grid;

	std::vector< std::vector< CParticle > > neighbors;
	std::vector<float> densities; //1D vector of densities (parallel to mPts)
	std::vector<Vector3df> colorField_gradient; //1D vector of gradient color fields (parallel to mPts)
	std::vector<float> colorField_laplacian; //1D vector of laplacian color fields (parallel to mPts)
	std::vector<Vector3df> pressureForces;
	std::vector<Vector3df> viscosityForces;
	std::vector<Vector3df> externalForces;
	std::vector<Vector3df> accelerations;
	

	std::vector<CParticle> particles;
};
